Load Packages

First I need to load up the packages I’ll need

library(sf)
library(ggplot2) #development version!
## devtools::install_github("tidyverse/ggplot2")
library(tidyverse)
library(readr)
## Not sure about this bit
#library("tidyverse",lib.loc="/Library/Frameworks/R.framework/Versions/3.4/Resources/library")
library(cowplot)
library(sp)
library(gridExtra)
library(dplyr)
library(ggrepel)
library(plyr)

Import Data

Now I import my data. I filter for the Arran postcodes, (since Arran all begins ‘KA27’).

## Finding the Arran coordinates
#allcoordinates <- read.csv("alldata/ukpostcodes.csv")
#arrancoordinates <- filter(allcoordinates,substr(postcode,1,4)=="KA27")
#arransubsect <- filter(pcs,substr(label,1,4)=="KA27")

Now I create some plots.

  ggplot() +
  geom_sf(data = arransubsect) +
  theme_grey() +
  geom_point(data = arrancoordinates, mapping = aes(x = longitude, y = latitude), size=1) +
  theme(axis.text.x=element_text(angle=45, hjust = 1)) +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))

Shape files

Now I load the SIMD data, containing the geometries (shapefiles) and SIMD data (percentiles, etc)

#Import SIMD data from http://www.gov.scot/Topics/Statistics/SIMD
#https://data.gov.uk/dataset/scottish-index-of-multiple-deprivation-simd-2012
#https://data.gov.uk/dataset/scottish-index-of-multiple-deprivation-simd-2012/resource/d6fa8924-83da-4e80-a560-4ef0477f230b
DZBoundaries2016 <- read_sf("./alldata/SG_SIMD_2016")
DZBoundaries2012 <- read_sf("./alldata/SG_SIMD_2012")
DZBoundaries2009 <- read_sf("./alldata/SG_SIMD_2009")
DZBoundaries2006 <- read_sf("./alldata/SG_SIMD_2006")
DZBoundaries2004 <- read_sf("./alldata/SG_SIMD_2004")

Select Arran SIMD data

I have to choose the right columns manually in order to select the Arran data.

#Selecting Arran data from Scotland (2016)
#Find postcode look-up from below file for KA27 postcodes. Find unique DZ. Find row positions.
#SIMD2016 <-read.csv("./alldata/00505244.csv")
#Selecting ArranDZ2016
Arrandz2016 <- c(4672,4666,4669,4671,4667,4668,4670)
arran2016 <- DZBoundaries2016[Arrandz2016,]
#Reorder arran 2016
reorderedvector<- c("S01011174", "S01011171", "S01011177", "S01011176", "S01011175", "S01011173", "S01011172" )
arran2016 <- arran2016 %>%
  slice(match(reorderedvector, DataZone))
#Find postcode look-up, KA27 postcodes. Find unique DZ. Find row positions.
#Selecting ArranDZ2012
Arrandz2012 <- c(4409,4372,4353,4352,4351,4350,4349)
#2012
arran2012 <- DZBoundaries2012[Arrandz2012,]
#2009
arran2009 <- DZBoundaries2009[Arrandz2012,]
#2006
arran2006 <- DZBoundaries2006[Arrandz2012,]
#2004
arran2004 <- DZBoundaries2004[Arrandz2012,]

Now I want to plot all the data, first I combine it all into one table. First I subselect the data I want from the appropriate columns.

arran20162 <- arran2016 %>%
  select(DataZone, geometry, Percentile)  %>%
  mutate(year="2016")
arran20122 <- arran2012 %>%
  select(DataZone, geometry, Percentile) %>%
  mutate(year="2012")
arran20092 <- arran2009 %>%
  select(DataZone, geometry, Percentile) %>%
  mutate(year="2009")
arran20062 <- arran2006 %>%
  select(DataZone, geometry, Percentile) %>%
  mutate(year="2006")
arran20042 <- arran2004 %>%
  select(DataZone, geometry, Percentile) %>%
  mutate(year="2004")
#Now I add it together
arransimd <- rbind(arran20162,arran20122,arran20092,arran20062,arran20042)

The reason I’ve downloaded all the datazones shapefiles individually is because they change between 2016 and 2012. See the small differences.

arran1612 <- rbind(arran20162,arran20122)
arran1612 %>%
  ggplot() +
  geom_sf(aes(fill = DataZone)) +
  facet_wrap('year') +
  theme_grey() +
  theme(legend.position="none") +
  theme(axis.text.x=element_text(angle=45, hjust = 1))

Arran Percentile Plots

Now I plot the percentiles.

arransimd %>%
  ggplot() +
  geom_sf(aes(fill = Percentile)) +
  facet_wrap('year', nrow = 1) +
  theme_grey() +
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank(), 
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank())

There we are. The SIMD health percentiles of Arran zones throughout SIMD history. And I’ve learned a little bit about graphics in R.

If I wanted to I could show the zones individually.. First I find the unique zones. (There are 14. 7 Zones 2016, 7 Zones pre-2016)

datazones <- unique(arransimd$DataZone)

I’ll have to find out a simpler way to do this but.. In order to turn the names into arguments I’ve made a function that filters the data into an individual name. #Pre-2016 Individual Zones

function0.5 <- function(argument) 
{
  filter(arransimd, DataZone==argument)
}

So by reading ‘datazones’ I’ve made a list of the output

#all datazones
datazonelist <- lapply(datazones, function0.5)
#Pre-2016 lists
pre2016list2 <- list("S01004409", "S01004372", "S01004353", "S01004352", "S01004351", "S01004350", "S01004349")
#Create a new way of making character list
pre2016list <- lapply(pre2016list2, function0.5)
post2016list2 <- list("S01011174", "S01011171", "S01011177", "S01011176", "S01011175", "S01011173", "S01011172")
post2016list <- lapply(post2016list2, function0.5)

Now I want to overlay the postcodes for a particular shapefile, in this case by Datazone. To do this I’ve converted both the Arran coordinates and Arran (2016) shapefiles into Spatial Points/Polygons, converted them into a common CRS, and then compared them by using over().

simple.sf <- st_as_sf(arrancoordinates, coords=c('longitude','latitude'))
st_crs(simple.sf) <- 4326
exampleshapes <- sf:::as_Spatial(arran2016$geometry)
examplepoints <- sf:::as_Spatial(simple.sf$geom)
examplepoints <- spTransform(examplepoints, CRS("+proj=longlat +datum=WGS84"))
exampleshapes <- spTransform(exampleshapes, CRS("+proj=longlat +datum=WGS84"))
namingdzpostcode <- over(exampleshapes, examplepoints, returnList = TRUE)

I can then take a member reference from the orginal postcode list, which gives me a selection of the rows in that DZ. For simplicity I’ve written this as a new function.

Unfortunately, I haven’t worked out how to coordinate the new ID with the original DZ names yet, so I have to select by using the appropriate ID for each DZ.

pre2016listID <- list(1,2,3,4,5,6,7)
post2016listID <- list(1,2,3,4,5,6,7)
listID <- list(1,2,3,4,5,6,7)

Function selecting simple.sf by DZ ID.

function6 <- function(argument) 
{
  arrancoordinates[namingdzpostcode[[argument]],]
}

mutate arrancoordinates

function100(S01004353)
Error in namingdzpostcode[[argument]] : invalid subscript type 'list'

I’ve also made another function to plot the DZ on it’s own with coordinates.

function5 <- function(argument, argument2) 
{
  argument %>%
  ggplot() +
  geom_sf() +
  theme_grey() +
  geom_point(data=function6(argument2), mapping = aes(x = longitude, y = latitude), size=1) +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))
}

OK at sufficiently sized exports. looks crowded in previews

function5.5 <- function(argument, argument2) 
{
  argument %>%
  ggplot() +
  geom_sf() +
  theme_grey() +
  geom_point(data=function6(argument2), mapping = aes(x = longitude, y = latitude), size=1) +
  geom_text_repel(data = function6(2), 
            aes(label = function6(2)$postcode, x = longitude, y = latitude), size=2) +
    theme(axis.title.x = element_blank(),
        axis.title.y = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))
}
function1.5.5 <- function(argument) 
{
  argument %>%
mutate(
    lon = map_dbl(geometry, ~st_centroid(.x)[[1]]),
    lat = map_dbl(geometry, ~st_centroid(.x)[[2]])
    ) %>%
  ggplot() +
  geom_sf(aes(fill = Percentile)) +
  facet_wrap('year') +
  theme_grey() +
  geom_text(aes(label = Percentile, x = lon, y = lat), size = 2, colour = "white") +
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank()) +
  theme(legend.position="bottom")  
}
function1.5.5(S01004372)

function2.5.1 <- function(argument) 
{
  arransubsect %>%
  ggplot() +
  geom_sf() +
  theme_grey() +
  theme(axis.text.x=element_text(angle=45, hjust = 1)) +
  theme(legend.position="bottom") +
  geom_sf(data= argument, aes(fill = DataZone))
}
function7.5.1 <- function(argument, argument2) 
{
  a <- function1.5.5(argument)
  b <- function2.5.1(argument) 
  c <- function5(argument, argument2)
  grid.arrange(a, b, c, nrow = 1)
}
function7.5.1(S01004372,2)

function8.pre <- function(argument)
{
  function7.5.1(pre2016list[[argument]],listID[[argument]])
}
lapply(1:7, function8.pre)
[[1]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[2]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[3]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[4]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[5]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[6]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[7]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

function8.post <- function(argument)
{
  function7.5.1(post2016list[[argument]],listID[[argument]])
}
lapply(1:7, function8.post)
[[1]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[2]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[3]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[4]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[5]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[6]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

[[7]]
TableGrob (1 x 3) "arrange": 3 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (1-1,2-2) arrange gtable[layout]
3 3 (1-1,3-3) arrange gtable[layout]

Front-Page Graphics

plot1 <- ggplot() +
  theme_grey() +
  geom_point(data = arrancoordinates, 
             mapping = aes(x = longitude, y = latitude), size=1) +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))
plot2 <- ggplot() +
  geom_sf(data = arransubsect) +
  theme_grey() +
  geom_point(data = arrancoordinates, 
             mapping = aes(x = longitude, y = latitude), size=1) +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))
plot3 <- ggplot() +
  geom_sf(data = arran2016) +
  theme_grey() +
  geom_point(data = arrancoordinates, 
             mapping = aes(x = longitude, y = latitude), size=1) +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))
plot4 <- ggplot() +
  geom_sf(data = arransubsect) +
  geom_sf(data= function0.5("S01004372")) +
  geom_point(data = arrancoordinates[namingdzpostcode[[2]],], 
             mapping = aes(x = longitude, y = latitude), size=1) +
  theme_grey() +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))
plot5 <- function0.5("S01004372") %>%
  ggplot() +
  geom_sf() +
  theme_grey() +
  geom_point(data = arrancoordinates[namingdzpostcode[[2]],], 
             mapping = aes(x = longitude, y = latitude), size=1) +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))
grid.arrange(plot1, plot2, plot3, plot4, plot5, nrow = 1)

plot6 <- arran2016 %>%
  ggplot() +
  geom_sf() +
  theme_grey() +
  theme(legend.position="none") +
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank())
plot7 <- arran2016 %>%
  ggplot() +
  geom_sf(aes(fill = DataZone)) +
  theme_grey() +
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank())
plot8 <- arran2016 %>%
  ggplot() +
  geom_sf(aes(fill = Percentile)) +
  theme_grey() +
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank())
grid.arrange(plot6, plot7, plot8, nrow = 1)

arransubsect %>%
  ggplot() +
  geom_sf() +
  theme_grey() +
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) +
  geom_sf(data= function0.5("S01004372")) +
  geom_point(data=function6(2), mapping = aes(x = longitude, y = latitude), size=1) +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank()) +
  coord_sf(crs= 4326, datum = sf::st_crs(4326))

#ID Postcodes
#Use to edit function5

Annotate percentile!

plot text of percentile, at centre of shape file coordinates.

overlay info onto leaflet then with labels.

LS0tCnRpdGxlOiAiQXJyYW4iCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KI0xvYWQgUGFja2FnZXMKRmlyc3QgSSBuZWVkIHRvIGxvYWQgdXAgdGhlIHBhY2thZ2VzIEknbGwgbmVlZApgYGB7cn0KbGlicmFyeShzZikKbGlicmFyeShnZ3Bsb3QyKSAjZGV2ZWxvcG1lbnQgdmVyc2lvbiEKIyMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJ0aWR5dmVyc2UvZ2dwbG90MiIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWRyKQojIyBOb3Qgc3VyZSBhYm91dCB0aGlzIGJpdAojbGlicmFyeSgidGlkeXZlcnNlIixsaWIubG9jPSIvTGlicmFyeS9GcmFtZXdvcmtzL1IuZnJhbWV3b3JrL1ZlcnNpb25zLzMuNC9SZXNvdXJjZXMvbGlicmFyeSIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShzcCkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShwbHlyKQpgYGAKCiNJbXBvcnQgRGF0YQpOb3cgSSBpbXBvcnQgbXkgZGF0YS4gSSBmaWx0ZXIgZm9yIHRoZSBBcnJhbiBwb3N0Y29kZXMsIChzaW5jZSBBcnJhbiBhbGwgYmVnaW5zICdLQTI3JykuCmBgYHtyfQojIyBGaW5kaW5nIHRoZSBBcnJhbiBjb29yZGluYXRlcwphcnJhbmNvb3JkaW5hdGVzIDwtIHJlYWQuY3N2KCJhbGxkYXRhL3VrcG9zdGNvZGVzLmNzdiIpICU+JQogZmlsdGVyKHN1YnN0cihwb3N0Y29kZSwxLDQpPT0iS0EyNyIpCgpwY3MgPC0gcmVhZF9zZigiYWxsZGF0YS9TY290bGFuZF9wY3NfMjAxMSIpCmFycmFuc3Vic2VjdCA8LSBmaWx0ZXIocGNzLHN1YnN0cihsYWJlbCwxLDQpPT0iS0EyNyIpCmBgYAoKTm93IEkgY3JlYXRlIHNvbWUgcGxvdHMuCmBgYHtyfQogIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSBhcnJhbnN1YnNlY3QpICsKICB0aGVtZV9ncmV5KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFycmFuY29vcmRpbmF0ZXMsIG1hcHBpbmcgPSBhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlKSwgc2l6ZT0xKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdCA9IDEpKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGNvb3JkX3NmKGNycz0gNDMyNiwgZGF0dW0gPSBzZjo6c3RfY3JzKDQzMjYpKQpgYGAKCiNTaGFwZSBmaWxlcwpOb3cgSSBsb2FkIHRoZSBTSU1EIGRhdGEsIGNvbnRhaW5pbmcgdGhlIGdlb21ldHJpZXMgKHNoYXBlZmlsZXMpIGFuZCBTSU1EIGRhdGEgKHBlcmNlbnRpbGVzLCBldGMpCmBgYHtyfQojSW1wb3J0IFNJTUQgZGF0YSBmcm9tIGh0dHA6Ly93d3cuZ292LnNjb3QvVG9waWNzL1N0YXRpc3RpY3MvU0lNRAojaHR0cHM6Ly9kYXRhLmdvdi51ay9kYXRhc2V0L3Njb3R0aXNoLWluZGV4LW9mLW11bHRpcGxlLWRlcHJpdmF0aW9uLXNpbWQtMjAxMgojaHR0cHM6Ly9kYXRhLmdvdi51ay9kYXRhc2V0L3Njb3R0aXNoLWluZGV4LW9mLW11bHRpcGxlLWRlcHJpdmF0aW9uLXNpbWQtMjAxMi9yZXNvdXJjZS9kNmZhODkyNC04M2RhLTRlODAtYTU2MC00ZWYwNDc3ZjIzMGIKRFpCb3VuZGFyaWVzMjAxNiA8LSByZWFkX3NmKCIuL2FsbGRhdGEvU0dfU0lNRF8yMDE2IikKRFpCb3VuZGFyaWVzMjAxMiA8LSByZWFkX3NmKCIuL2FsbGRhdGEvU0dfU0lNRF8yMDEyIikKRFpCb3VuZGFyaWVzMjAwOSA8LSByZWFkX3NmKCIuL2FsbGRhdGEvU0dfU0lNRF8yMDA5IikKRFpCb3VuZGFyaWVzMjAwNiA8LSByZWFkX3NmKCIuL2FsbGRhdGEvU0dfU0lNRF8yMDA2IikKRFpCb3VuZGFyaWVzMjAwNCA8LSByZWFkX3NmKCIuL2FsbGRhdGEvU0dfU0lNRF8yMDA0IikKYGBgCgojU2VsZWN0IEFycmFuIFNJTUQgZGF0YQpJIGhhdmUgdG8gY2hvb3NlIHRoZSByaWdodCBjb2x1bW5zIG1hbnVhbGx5IGluIG9yZGVyIHRvIHNlbGVjdCB0aGUgQXJyYW4gZGF0YS4KYGBge3J9CiNTZWxlY3RpbmcgQXJyYW4gZGF0YSBmcm9tIFNjb3RsYW5kICgyMDE2KQojRmluZCBwb3N0Y29kZSBsb29rLXVwIGZyb20gYmVsb3cgZmlsZSBmb3IgS0EyNyBwb3N0Y29kZXMuIEZpbmQgdW5pcXVlIERaLiBGaW5kIHJvdyBwb3NpdGlvbnMuCiNTSU1EMjAxNiA8LXJlYWQuY3N2KCIuL2FsbGRhdGEvMDA1MDUyNDQuY3N2IikKI1NlbGVjdGluZyBBcnJhbkRaMjAxNgpBcnJhbmR6MjAxNiA8LSBjKDQ2NzIsNDY2Niw0NjY5LDQ2NzEsNDY2Nyw0NjY4LDQ2NzApCmFycmFuMjAxNiA8LSBEWkJvdW5kYXJpZXMyMDE2W0FycmFuZHoyMDE2LF0KI1Jlb3JkZXIgYXJyYW4gMjAxNgpyZW9yZGVyZWR2ZWN0b3I8LSBjKCJTMDEwMTExNzQiLCAiUzAxMDExMTcxIiwgIlMwMTAxMTE3NyIsICJTMDEwMTExNzYiLCAiUzAxMDExMTc1IiwgIlMwMTAxMTE3MyIsICJTMDEwMTExNzIiICkKYXJyYW4yMDE2IDwtIGFycmFuMjAxNiAlPiUKICBzbGljZShtYXRjaChyZW9yZGVyZWR2ZWN0b3IsIERhdGFab25lKSkKCiNGaW5kIHBvc3Rjb2RlIGxvb2stdXAsIEtBMjcgcG9zdGNvZGVzLiBGaW5kIHVuaXF1ZSBEWi4gRmluZCByb3cgcG9zaXRpb25zLgojU2VsZWN0aW5nIEFycmFuRFoyMDEyCkFycmFuZHoyMDEyIDwtIGMoNDQwOSw0MzcyLDQzNTMsNDM1Miw0MzUxLDQzNTAsNDM0OSkKCiMyMDEyCmFycmFuMjAxMiA8LSBEWkJvdW5kYXJpZXMyMDEyW0FycmFuZHoyMDEyLF0KIzIwMDkKYXJyYW4yMDA5IDwtIERaQm91bmRhcmllczIwMDlbQXJyYW5kejIwMTIsXQojMjAwNgphcnJhbjIwMDYgPC0gRFpCb3VuZGFyaWVzMjAwNltBcnJhbmR6MjAxMixdCiMyMDA0CmFycmFuMjAwNCA8LSBEWkJvdW5kYXJpZXMyMDA0W0FycmFuZHoyMDEyLF0KYGBgCgpOb3cgSSB3YW50IHRvIHBsb3QgYWxsIHRoZSBkYXRhLCBmaXJzdCBJIGNvbWJpbmUgaXQgYWxsIGludG8gb25lIHRhYmxlLgpGaXJzdCBJIHN1YnNlbGVjdCB0aGUgZGF0YSBJIHdhbnQgZnJvbSB0aGUgYXBwcm9wcmlhdGUgY29sdW1ucy4KYGBge3J9CmFycmFuMjAxNjIgPC0gYXJyYW4yMDE2ICU+JQogIHNlbGVjdChEYXRhWm9uZSwgZ2VvbWV0cnksIFBlcmNlbnRpbGUpICAlPiUKICBtdXRhdGUoeWVhcj0iMjAxNiIpCgphcnJhbjIwMTIyIDwtIGFycmFuMjAxMiAlPiUKICBzZWxlY3QoRGF0YVpvbmUsIGdlb21ldHJ5LCBQZXJjZW50aWxlKSAlPiUKICBtdXRhdGUoeWVhcj0iMjAxMiIpCgphcnJhbjIwMDkyIDwtIGFycmFuMjAwOSAlPiUKICBzZWxlY3QoRGF0YVpvbmUsIGdlb21ldHJ5LCBQZXJjZW50aWxlKSAlPiUKICBtdXRhdGUoeWVhcj0iMjAwOSIpCgphcnJhbjIwMDYyIDwtIGFycmFuMjAwNiAlPiUKICBzZWxlY3QoRGF0YVpvbmUsIGdlb21ldHJ5LCBQZXJjZW50aWxlKSAlPiUKICBtdXRhdGUoeWVhcj0iMjAwNiIpCgphcnJhbjIwMDQyIDwtIGFycmFuMjAwNCAlPiUKICBzZWxlY3QoRGF0YVpvbmUsIGdlb21ldHJ5LCBQZXJjZW50aWxlKSAlPiUKICBtdXRhdGUoeWVhcj0iMjAwNCIpCgojTm93IEkgYWRkIGl0IHRvZ2V0aGVyCmFycmFuc2ltZCA8LSByYmluZChhcnJhbjIwMTYyLGFycmFuMjAxMjIsYXJyYW4yMDA5MixhcnJhbjIwMDYyLGFycmFuMjAwNDIpCmBgYAoKVGhlIHJlYXNvbiBJJ3ZlIGRvd25sb2FkZWQgYWxsIHRoZSBkYXRhem9uZXMgc2hhcGVmaWxlcyBpbmRpdmlkdWFsbHkgaXMgYmVjYXVzZSB0aGV5IGNoYW5nZSBiZXR3ZWVuIDIwMTYgYW5kIDIwMTIuClNlZSB0aGUgc21hbGwgZGlmZmVyZW5jZXMuCmBgYHtyfQphcnJhbjE2MTIgPC0gcmJpbmQoYXJyYW4yMDE2MixhcnJhbjIwMTIyKQoKYXJyYW4xNjEyICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gRGF0YVpvbmUpKSArCiAgZmFjZXRfd3JhcCgneWVhcicpICsKICB0aGVtZV9ncmV5KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0ID0gMSkpCmBgYAoKI0FycmFuIFBlcmNlbnRpbGUgUGxvdHMKTm93IEkgcGxvdCB0aGUgcGVyY2VudGlsZXMuCmBgYHtyfQphcnJhbnNpbWQgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGwgPSBQZXJjZW50aWxlKSkgKwogIGZhY2V0X3dyYXAoJ3llYXInLCBucm93ID0gMSkgKwogIHRoZW1lX2dyZXkoKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpKQpgYGAKClRoZXJlIHdlIGFyZS4gVGhlIFNJTUQgaGVhbHRoIHBlcmNlbnRpbGVzIG9mIEFycmFuIHpvbmVzIHRocm91Z2hvdXQgU0lNRCBoaXN0b3J5LiBBbmQgSSd2ZSBsZWFybmVkIGEgbGl0dGxlIGJpdCBhYm91dCBncmFwaGljcyBpbiBSLgoKSWYgSSB3YW50ZWQgdG8gSSBjb3VsZCBzaG93IHRoZSB6b25lcyBpbmRpdmlkdWFsbHkuLgpGaXJzdCBJIGZpbmQgdGhlIHVuaXF1ZSB6b25lcy4gKFRoZXJlIGFyZSAxNC4gNyBab25lcyAyMDE2LCA3IFpvbmVzIHByZS0yMDE2KQoKYGBge3J9CmRhdGF6b25lcyA8LSB1bmlxdWUoYXJyYW5zaW1kJERhdGFab25lKQpgYGAKCkknbGwgaGF2ZSB0byBmaW5kIG91dCBhIHNpbXBsZXIgd2F5IHRvIGRvIHRoaXMgYnV0Li4gSW4gb3JkZXIgdG8gdHVybiB0aGUgbmFtZXMgaW50byBhcmd1bWVudHMgSSd2ZSBtYWRlIGEgZnVuY3Rpb24gdGhhdCBmaWx0ZXJzIHRoZSBkYXRhIGludG8gYW4gaW5kaXZpZHVhbCBuYW1lLgojUHJlLTIwMTYgSW5kaXZpZHVhbCBab25lcwpgYGB7cn0KZnVuY3Rpb24wLjUgPC0gZnVuY3Rpb24oYXJndW1lbnQpIAp7CiAgZmlsdGVyKGFycmFuc2ltZCwgRGF0YVpvbmU9PWFyZ3VtZW50KQp9CmBgYAoKU28gYnkgcmVhZGluZyAnZGF0YXpvbmVzJyBJJ3ZlIG1hZGUgYSBsaXN0IG9mIHRoZSBvdXRwdXQgCmBgYHtyfQojYWxsIGRhdGF6b25lcwpkYXRhem9uZWxpc3QgPC0gbGFwcGx5KGRhdGF6b25lcywgZnVuY3Rpb24wLjUpCgojUHJlLTIwMTYgbGlzdHMKcHJlMjAxNmxpc3QyIDwtIGxpc3QoIlMwMTAwNDQwOSIsICJTMDEwMDQzNzIiLCAiUzAxMDA0MzUzIiwgIlMwMTAwNDM1MiIsICJTMDEwMDQzNTEiLCAiUzAxMDA0MzUwIiwgIlMwMTAwNDM0OSIpCiNDcmVhdGUgYSBuZXcgd2F5IG9mIG1ha2luZyBjaGFyYWN0ZXIgbGlzdApwcmUyMDE2bGlzdCA8LSBsYXBwbHkocHJlMjAxNmxpc3QyLCBmdW5jdGlvbjAuNSkKCnBvc3QyMDE2bGlzdDIgPC0gbGlzdCgiUzAxMDExMTc0IiwgIlMwMTAxMTE3MSIsICJTMDEwMTExNzciLCAiUzAxMDExMTc2IiwgIlMwMTAxMTE3NSIsICJTMDEwMTExNzMiLCAiUzAxMDExMTcyIikKcG9zdDIwMTZsaXN0IDwtIGxhcHBseShwb3N0MjAxNmxpc3QyLCBmdW5jdGlvbjAuNSkKYGBgCgoKTm93IEkgd2FudCB0byBvdmVybGF5IHRoZSBwb3N0Y29kZXMgZm9yIGEgcGFydGljdWxhciBzaGFwZWZpbGUsIGluIHRoaXMgY2FzZSBieSBEYXRhem9uZS4KVG8gZG8gdGhpcyBJJ3ZlIGNvbnZlcnRlZCBib3RoIHRoZSBBcnJhbiBjb29yZGluYXRlcyBhbmQgQXJyYW4gKDIwMTYpIHNoYXBlZmlsZXMgaW50byBTcGF0aWFsIFBvaW50cy9Qb2x5Z29ucywgY29udmVydGVkIHRoZW0gaW50byBhIGNvbW1vbiBDUlMsIGFuZCB0aGVuIGNvbXBhcmVkIHRoZW0gYnkgdXNpbmcgb3ZlcigpLgpgYGB7cn0Kc2ltcGxlLnNmIDwtIHN0X2FzX3NmKGFycmFuY29vcmRpbmF0ZXMsIGNvb3Jkcz1jKCdsb25naXR1ZGUnLCdsYXRpdHVkZScpKQpzdF9jcnMoc2ltcGxlLnNmKSA8LSA0MzI2CgpleGFtcGxlc2hhcGVzIDwtIHNmOjo6YXNfU3BhdGlhbChhcnJhbjIwMTYkZ2VvbWV0cnkpCmV4YW1wbGVwb2ludHMgPC0gc2Y6Ojphc19TcGF0aWFsKHNpbXBsZS5zZiRnZW9tKQoKZXhhbXBsZXBvaW50cyA8LSBzcFRyYW5zZm9ybShleGFtcGxlcG9pbnRzLCBDUlMoIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikpCmV4YW1wbGVzaGFwZXMgPC0gc3BUcmFuc2Zvcm0oZXhhbXBsZXNoYXBlcywgQ1JTKCIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCIpKQoKbmFtaW5nZHpwb3N0Y29kZSA8LSBvdmVyKGV4YW1wbGVzaGFwZXMsIGV4YW1wbGVwb2ludHMsIHJldHVybkxpc3QgPSBUUlVFKQpgYGAKCkkgY2FuIHRoZW4gdGFrZSBhIG1lbWJlciByZWZlcmVuY2UgZnJvbSB0aGUgb3JnaW5hbCBwb3N0Y29kZSBsaXN0LCB3aGljaCBnaXZlcyBtZSBhIHNlbGVjdGlvbiBvZiB0aGUgcm93cyBpbiB0aGF0IERaLiBGb3Igc2ltcGxpY2l0eSBJJ3ZlIHdyaXR0ZW4gdGhpcyBhcyBhIG5ldyBmdW5jdGlvbi4gCgpVbmZvcnR1bmF0ZWx5LCBJIGhhdmVuJ3Qgd29ya2VkIG91dCBob3cgdG8gY29vcmRpbmF0ZSB0aGUgbmV3IElEIHdpdGggdGhlIG9yaWdpbmFsIERaIG5hbWVzIHlldCwgc28gSSBoYXZlIHRvIHNlbGVjdCBieSB1c2luZyB0aGUgYXBwcm9wcmlhdGUgSUQgZm9yIGVhY2ggRFouCmBgYHtyfQpwcmUyMDE2bGlzdElEIDwtIGxpc3QoMSwyLDMsNCw1LDYsNykKcG9zdDIwMTZsaXN0SUQgPC0gbGlzdCgxLDIsMyw0LDUsNiw3KQoKbGlzdElEIDwtIGxpc3QoMSwyLDMsNCw1LDYsNykKYGBgCgojRnVuY3Rpb24gc2VsZWN0aW5nIHNpbXBsZS5zZiBieSBEWiBJRC4KYGBge3J9CmZ1bmN0aW9uNiA8LSBmdW5jdGlvbihhcmd1bWVudCkgCnsKICBhcnJhbmNvb3JkaW5hdGVzW25hbWluZ2R6cG9zdGNvZGVbW2FyZ3VtZW50XV0sXQp9CmBgYAoKI211dGF0ZSBhcnJhbmNvb3JkaW5hdGVzCmBgYHtyfQpmdW5jdGlvbjEwMCA8LSBmdW5jdGlvbihhcmd1bWVudCkgCnsKICBhcmd1bWVudCA8LSBhcnJhbmNvb3JkaW5hdGVzW25hbWluZ2R6cG9zdGNvZGVbW2FyZ3VtZW50XV0sXSAlPiUgbXV0YXRlKERhdGFab25lPWFyZ3VtZW50KQp9CgpmdW5jdGlvbjEwMCgxKQoKbmV3YXJyYW5jb29yZGluYXRlcyA8LSBsYXBwbHkoMTo3LGZ1bmN0aW9uMTAwKQpuZXdhcnJhbmNvb3JkaW5hdGVzIDwtIHJiaW5kKG5ld2FycmFuY29vcmRpbmF0ZXNbWzFdXSwgbmV3YXJyYW5jb29yZGluYXRlc1tbMl1dLCBuZXdhcnJhbmNvb3JkaW5hdGVzW1szXV0sIG5ld2FycmFuY29vcmRpbmF0ZXNbWzRdXSwgbmV3YXJyYW5jb29yZGluYXRlc1tbNV1dLCBuZXdhcnJhbmNvb3JkaW5hdGVzW1s2XV0sIG5ld2FycmFuY29vcmRpbmF0ZXNbWzddXSkKCm5ld2FycmFuY29vcmRpbmF0ZXMkbGlzdElEIDwtIHJldmFsdWUoYXMuY2hhcmFjdGVyKG5ld2FycmFuY29vcmRpbmF0ZXMkRGF0YVpvbmUpLAogICAgICAgICAgICAgICBjKCcxJz0iUzAxMDA0NDA5L1MwMTAxMTE3NCIsICcyJz0iUzAxMDA0MzcyL1MwMTAxMTE3MSIsICczJz0iUzAxMDA0MzUzL1MwMTAxMTE3NyIsICc0Jz0iUzAxMDA0MzUyL1MwMTAxMTE3NiIsICc1Jz0iUzAxMDA0MzUxL1MwMTAxMTE3NSIsICc2Jz0iUzAxMDA0MzUwL1MwMTAxMTE3MyIsICc3Jz0iUzAxMDA0MzQ5L1MwMTAxMTE3MiIpKQpgYGAKCkkndmUgYWxzbyBtYWRlIGFub3RoZXIgZnVuY3Rpb24gdG8gcGxvdCB0aGUgRFogb24gaXQncyBvd24gd2l0aCBjb29yZGluYXRlcy4KYGBge3J9CmZ1bmN0aW9uNSA8LSBmdW5jdGlvbihhcmd1bWVudCwgYXJndW1lbnQyKSAKewogIGFyZ3VtZW50ICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKCkgKwogIHRoZW1lX2dyZXkoKSArCiAgZ2VvbV9wb2ludChkYXRhPWZ1bmN0aW9uNihhcmd1bWVudDIpLCBtYXBwaW5nID0gYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSksIHNpemU9MSkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBjb29yZF9zZihjcnM9IDQzMjYsIGRhdHVtID0gc2Y6OnN0X2Nycyg0MzI2KSkKfQpgYGAKCiNPSyBhdCBzdWZmaWNpZW50bHkgc2l6ZWQgZXhwb3J0cy4gbG9va3MgY3Jvd2RlZCBpbiBwcmV2aWV3cwpgYGB7cn0KZnVuY3Rpb241LjUgPC0gZnVuY3Rpb24oYXJndW1lbnQsIGFyZ3VtZW50MikgCnsKICBhcmd1bWVudCAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZigpICsKICB0aGVtZV9ncmV5KCkgKwogIGdlb21fcG9pbnQoZGF0YT1mdW5jdGlvbjYoYXJndW1lbnQyKSwgbWFwcGluZyA9IGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUpLCBzaXplPTEpICsKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGZ1bmN0aW9uNigyKSwgCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IGZ1bmN0aW9uNigyKSRwb3N0Y29kZSwgeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlKSwgc2l6ZT0yKSArCiAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgY29vcmRfc2YoY3JzPSA0MzI2LCBkYXR1bSA9IHNmOjpzdF9jcnMoNDMyNikpCn0KYGBgCgpgYGB7cn0KZnVuY3Rpb24xLjUuNSA8LSBmdW5jdGlvbihhcmd1bWVudCkgCnsKICBhcmd1bWVudCAlPiUKbXV0YXRlKAogICAgbG9uID0gbWFwX2RibChnZW9tZXRyeSwgfnN0X2NlbnRyb2lkKC54KVtbMV1dKSwKICAgIGxhdCA9IG1hcF9kYmwoZ2VvbWV0cnksIH5zdF9jZW50cm9pZCgueClbWzJdXSkKICAgICkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGwgPSBQZXJjZW50aWxlKSkgKwogIGZhY2V0X3dyYXAoJ3llYXInKSArCiAgdGhlbWVfZ3JleSgpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gUGVyY2VudGlsZSwgeCA9IGxvbiwgeSA9IGxhdCksIHNpemUgPSAyLCBjb2xvdXIgPSAid2hpdGUiKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgIAp9CmBgYAoKYGBge3J9CmZ1bmN0aW9uMS41LjUoUzAxMDA0MzcyKQpgYGAKCmBgYHtyfQpmdW5jdGlvbjIuNS4xIDwtIGZ1bmN0aW9uKGFyZ3VtZW50KSAKewogIGFycmFuc3Vic2VjdCAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZigpICsKICB0aGVtZV9ncmV5KCkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPSAxKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGdlb21fc2YoZGF0YT0gYXJndW1lbnQsIGFlcyhmaWxsID0gRGF0YVpvbmUpKQp9CmBgYAoKYGBge3J9CmZ1bmN0aW9uNy41LjEgPC0gZnVuY3Rpb24oYXJndW1lbnQsIGFyZ3VtZW50MikgCnsKICBhIDwtIGZ1bmN0aW9uMS41LjUoYXJndW1lbnQpCiAgYiA8LSBmdW5jdGlvbjIuNS4xKGFyZ3VtZW50KSAKICBjIDwtIGZ1bmN0aW9uNShhcmd1bWVudCwgYXJndW1lbnQyKQogIGdyaWQuYXJyYW5nZShhLCBiLCBjLCBucm93ID0gMSkKfQpgYGAKCmBgYHtyfQpmdW5jdGlvbjcuNS4xKFMwMTAwNDM3MiwyKQpgYGAKCmBgYHtyfQpmdW5jdGlvbjgucHJlIDwtIGZ1bmN0aW9uKGFyZ3VtZW50KQp7CiAgZnVuY3Rpb243LjUuMShwcmUyMDE2bGlzdFtbYXJndW1lbnRdXSxsaXN0SURbW2FyZ3VtZW50XV0pCn0KbGFwcGx5KDE6NywgZnVuY3Rpb244LnByZSkKCmZ1bmN0aW9uOC5wb3N0IDwtIGZ1bmN0aW9uKGFyZ3VtZW50KQp7CiAgZnVuY3Rpb243LjUuMShwb3N0MjAxNmxpc3RbW2FyZ3VtZW50XV0sbGlzdElEW1thcmd1bWVudF1dKQp9CmxhcHBseSgxOjcsIGZ1bmN0aW9uOC5wb3N0KQpgYGAKCiNGcm9udC1QYWdlIEdyYXBoaWNzCmBgYHtyfQpwbG90MSA8LSBnZ3Bsb3QoKSArCiAgdGhlbWVfZ3JleSgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcnJhbmNvb3JkaW5hdGVzLCAKICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlKSwgc2l6ZT0xKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICBjb29yZF9zZihjcnM9IDQzMjYsIGRhdHVtID0gc2Y6OnN0X2Nycyg0MzI2KSkKCnBsb3QyIDwtIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSBhcnJhbnN1YnNlY3QpICsKICB0aGVtZV9ncmV5KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFycmFuY29vcmRpbmF0ZXMsIAogICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUpLCBzaXplPTEpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGNvb3JkX3NmKGNycz0gNDMyNiwgZGF0dW0gPSBzZjo6c3RfY3JzKDQzMjYpKQoKcGxvdDMgPC0gZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IGFycmFuMjAxNikgKwogIHRoZW1lX2dyZXkoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXJyYW5jb29yZGluYXRlcywgCiAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSksIHNpemU9MSkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgY29vcmRfc2YoY3JzPSA0MzI2LCBkYXR1bSA9IHNmOjpzdF9jcnMoNDMyNikpCgpwbG90NCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhID0gYXJyYW5zdWJzZWN0KSArCiAgZ2VvbV9zZihkYXRhPSBmdW5jdGlvbjAuNSgiUzAxMDA0MzcyIikpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcnJhbmNvb3JkaW5hdGVzW25hbWluZ2R6cG9zdGNvZGVbWzJdXSxdLCAKICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlKSwgc2l6ZT0xKSArCiAgdGhlbWVfZ3JleSgpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGNvb3JkX3NmKGNycz0gNDMyNiwgZGF0dW0gPSBzZjo6c3RfY3JzKDQzMjYpKQoKcGxvdDUgPC0gZnVuY3Rpb24wLjUoIlMwMTAwNDM3MiIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKCkgKwogIHRoZW1lX2dyZXkoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXJyYW5jb29yZGluYXRlc1tuYW1pbmdkenBvc3Rjb2RlW1syXV0sXSwgCiAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSksIHNpemU9MSkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgY29vcmRfc2YoY3JzPSA0MzI2LCBkYXR1bSA9IHNmOjpzdF9jcnMoNDMyNikpCgpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBwbG90MywgcGxvdDQsIHBsb3Q1LCBucm93ID0gMSkKYGBgCgpgYGB7cn0KcGxvdDYgPC0gYXJyYW4yMDE2ICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKCkgKwogIHRoZW1lX2dyZXkoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKQoKcGxvdDcgPC0gYXJyYW4yMDE2ICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gRGF0YVpvbmUpKSArCiAgdGhlbWVfZ3JleSgpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkKCnBsb3Q4IDwtIGFycmFuMjAxNiAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbCA9IFBlcmNlbnRpbGUpKSArCiAgdGhlbWVfZ3JleSgpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkKCmdyaWQuYXJyYW5nZShwbG90NiwgcGxvdDcsIHBsb3Q4LCBucm93ID0gMSkKYGBgCgpgYGB7cn0KYXJyYW5zdWJzZWN0ICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKCkgKwogIHRoZW1lX2dyZXkoKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCkpICsKICBnZW9tX3NmKGRhdGE9IGZ1bmN0aW9uMC41KCJTMDEwMDQzNzIiKSkgKwogIGdlb21fcG9pbnQoZGF0YT1mdW5jdGlvbjYoMiksIG1hcHBpbmcgPSBhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlKSwgc2l6ZT0xKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGNvb3JkX3NmKGNycz0gNDMyNiwgZGF0dW0gPSBzZjo6c3RfY3JzKDQzMjYpKQoKI0lEIFBvc3Rjb2RlcwojVXNlIHRvIGVkaXQgZnVuY3Rpb241CmBgYAoKCiNBbm5vdGF0ZSBwZXJjZW50aWxlIQpwbG90IHRleHQgb2YgcGVyY2VudGlsZSwgYXQgY2VudHJlIG9mIHNoYXBlIGZpbGUgY29vcmRpbmF0ZXMuCgpvdmVybGF5IGluZm8gb250byBsZWFmbGV0CiB0aGVuIHdpdGggbGFiZWxzLgo=